<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Canvas 文本编辑与样式示例</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <style>
        body {
            margin: 20px;
        }
        canvas {
            border: 1px solid #000;
        }
        canvas:focus {
            outline: none;
        }
    </style>
</head>
<body>

<canvas id="myCanvas" width="800" height="300" tabindex="0"></canvas>

<script>
$(document).ready(function() {
    var canvas = $('#myCanvas')[0];
    var ctx = canvas.getContext('2d');
    var cursorPositionX = 0;
    var fullText = '欢迎您的到来！';
    var blinkInterval;
    var cursorVisible = false;
    var textMetrics = [];
    var isComposing = false; // 用于跟踪IME输入状态

    var styles = [
        { start: 0, end: 4, fontSize: '20px', fontFamily: 'Arial', color: 'black' },
        { start: 4, end: fullText.length, fontSize: '24px', fontFamily: 'Verdana', color: 'blue' }
    ];

    const defaultStyle = { fontSize: '20px', fontFamily: 'Arial', color: 'black' };

    function applyStyle(style) {
        ctx.font = `${style.fontSize} ${style.fontFamily}`;
        ctx.fillStyle = style.color;
    }

    function getStyleAtIndex(index) {
        if (fullText.length === 0 || styles.length === 0) {
            return defaultStyle;
        }

        if (index >= fullText.length) {
            return styles[styles.length - 1];
        }

        return styles.find(style => index >= style.start && index < style.end) || defaultStyle;
    }

    function updateTextMetrics() {
        textMetrics = [];
        var x = 10;
        for (let i = 0; i < fullText.length; i++) {
            let char = fullText[i];
            let style = getStyleAtIndex(i);
            applyStyle(style);
            let width = ctx.measureText(char).width;
            textMetrics.push({ x, width });
            x += width;
        }
    }

    function drawTextAndCursor() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        var x = 10;
        var y = 100;

        fullText.split('').forEach((char, index) => {
            var style = getStyleAtIndex(index);
            applyStyle(style);
            ctx.fillText(char, x, y);
            var metrics = ctx.measureText(char);
            x += metrics.width;
        });

        if (cursorVisible) {
            let cursorX = textMetrics[cursorPositionX] ? textMetrics[cursorPositionX].x : (textMetrics.length > 0 ? textMetrics[textMetrics.length - 1].x + textMetrics[textMetrics.length - 1].width : 10);
            ctx.beginPath();
            ctx.moveTo(cursorX, y - 20);
            ctx.lineTo(cursorX, y);
            ctx.stroke();
        }
    }

    function toggleCursorVisibility() {
        cursorVisible = !cursorVisible;
        drawTextAndCursor();
    }

    function handleTextInput(text) {
        fullText = fullText.substring(0, cursorPositionX) + text + fullText.substring(cursorPositionX);
        cursorPositionX += text.length;
        updateTextMetrics();
        drawTextAndCursor();
    }

    $(canvas).on('compositionstart', function(e) {
        isComposing = true;
    });

    $(canvas).on('compositionend', function(e) {
        isComposing = false;
        handleTextInput(e.originalEvent.data);
    });

    $(canvas).keydown(function(e) {
        if (!isComposing) {
            if (e.key.length === 1) {
                handleTextInput(e.key);
            } else if (e.key === 'Backspace') {
                if (cursorPositionX > 0) {
                    fullText = fullText.substring(0, cursorPositionX - 1) + fullText.substring(cursorPositionX);
                    cursorPositionX--;
                }
                updateTextMetrics();
                drawTextAndCursor();
            } else if (e.key === 'ArrowLeft') {
                cursorPositionX = Math.max(0, cursorPositionX - 1);
                drawTextAndCursor();
            } else if (e.key === 'ArrowRight') {
                cursorPositionX = Math.min(fullText.length, cursorPositionX + 1);
                drawTextAndCursor();
            }
            e.preventDefault();
        }
    });

    $(canvas).click(function(e) {
        var mouseX = e.pageX - $(this).offset().left;
        var closestIndex = textMetrics.findIndex(m => mouseX < m.x + m.width);
        cursorPositionX = closestIndex !== -1 ? closestIndex : fullText.length;
        clearInterval(blinkInterval);
        blinkInterval = setInterval(toggleCursorVisibility, 530);
        drawTextAndCursor();
    });

    updateTextMetrics();
    drawTextAndCursor(); // Initial draw
    blinkInterval = setInterval(toggleCursorVisibility, 530);
});
</script>

</body>
</html>
